package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CategoryClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CategoryBasicDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.NoteDTO;
import com.tianji.learning.domain.po.Note;
import com.tianji.learning.domain.po.NoteUser;
import com.tianji.learning.domain.query.AdminNotePageQuery;
import com.tianji.learning.domain.query.NotePageQuery;
import com.tianji.learning.domain.vo.AdminNoteDetailVO;
import com.tianji.learning.domain.vo.AdminNoteVO;
import com.tianji.learning.domain.vo.NoteVO;
import com.tianji.learning.mapper.NoteMapper;
import com.tianji.learning.service.INoteService;
import com.tianji.learning.service.INoteUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 笔记表 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-04-25
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class NoteServiceImpl extends ServiceImpl<NoteMapper, Note> implements INoteService {
    private final UserClient userClient;
    private final INoteUserService noteUserService;
    private final CourseClient courseClient;
    private final CatalogueClient catalogueClient;
    private final CategoryClient categoryClient;

    @Override
    public void saveNote(NoteDTO noteDTO) {
        //1.获取当前登录用户id
        Long userId = UserContext.getUser();
        //2.将dto转换为po
        Note note = BeanUtil.copyProperties(noteDTO, Note.class);
        note.setUserId(userId);
        save(note);
    }

    @Override
    public void gatherNote(Long id) {
        //1.根据笔记id查询笔记信息
        Note GatheredNote = getById(id);
        if (GatheredNote == null){
            throw new BizIllegalException("采集的信息有错误");
        }
        //2.封装po
        Note note = new Note();
        note.setContent(GatheredNote.getContent());
        note.setUserId(UserContext.getUser());
        note.setAuthorId(GatheredNote.getUserId());
        note.setIsGathered(true);
        note.setGatheredNoteId(id);
        note.setCourseId(GatheredNote.getCourseId());
        note.setChapterId(GatheredNote.getChapterId());
        note.setSectionId(GatheredNote.getSectionId());
        note.setNoteMoment(GatheredNote.getNoteMoment());
        //3.保存到数据库
        save(note);
        //4.保存到用户笔记关联表
        NoteUser noteUser = new NoteUser();
        //2.设置关联信息 存的笔记id是被采集的笔记id
        noteUser.setNoteId(id);
        noteUser.setUserId(UserContext.getUser());
        noteUser.setIsGathered(true);
        noteUserService.save(noteUser);
    }

    @Override
    public void cancelGatherNote(Long id) {
        //1.获取当前用户id
        Long userId = UserContext.getUser();
        //根据用户id删除被采集的笔记记录
       /* remove(new LambdaQueryWrapper<Note>()
                .eq(Note::getUserId, userId)
                .eq(Note::getGatheredNoteId, id)
        );*/
        this.lambdaUpdate().eq(Note::getGatheredNoteId, id).eq(Note::getUserId, userId).remove();
        noteUserService.lambdaUpdate().eq(NoteUser::getNoteId, id).eq(NoteUser::getUserId, userId).remove();
    }

    @Override
    public void updateNote(Long id, NoteDTO noteDTO) {
        Note note = BeanUtil.copyProperties(noteDTO, Note.class);
        note.setId(id);
        updateById(note);
    }

    @Override
    public PageDTO<NoteVO> queryNote(NotePageQuery query) {
        //1.获取当前登录用户id
        Long userId = UserContext.getUser();
        //2.判断是查询我的笔记还是全部笔记
        PageDTO<NoteVO> list=null;
        if (query.getOnlyMine()){
            //查询我的笔记
            list = queryMyNote(query, userId);
        }else{
            //查询全部笔记
            list = queryAllNote(query, userId);
        }
        return list;
    }
    private PageDTO<NoteVO> queryAllNote(NotePageQuery query, Long userId) {
        Page<Note> page = lambdaQuery()
                .eq(query.getCourseId() != null, Note::getCourseId, query.getCourseId())
                .eq(query.getSectionId() != null, Note::getSectionId, query.getSectionId())
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<Note> records = page.getRecords();
        if (CollUtil.isEmpty(records)){
            return PageDTO.empty(page);
        }
        //1.通过stream获取用户id集合
        List<Long> userIds = records.stream().map(Note::getUserId).collect(Collectors.toList());
        //3.根据id集合查询用户信息
        List<UserDTO> users = userClient.queryUserByIds(userIds);
        //3.1将用户信息转为map
        Map<Long, UserDTO> map = users.stream().collect(Collectors.toMap(UserDTO::getId, user -> user));
        //4.关联用户笔记表查询信息
        //4.1通过stream获取笔记id集合 用于判断当前笔记是否被当前用户采集，放到前端高亮显示
        List<Long> noteIds = records.stream().map(Note::getId).collect(Collectors.toList());
        List<NoteUser> noteUsers = noteUserService.lambdaQuery()
                .eq(NoteUser::getUserId, userId)
                .in(NoteUser::getNoteId, noteIds)
                .list();
        //4.2利用stream流获取map
        Map<Long, NoteUser> noteUsersMap = noteUsers.stream().collect(Collectors.toMap(NoteUser::getNoteId, noteUser -> noteUser));
        ArrayList<NoteVO> list = new ArrayList<>(records.size());
        for (Note record : records) {
            NoteVO vo = new NoteVO();
            //隐私笔记不展示到全部
            if (!userId.equals(record.getUserId()) && record.getIsPrivate()){
                continue;
            }
           /* //当前用户已采集的笔记不应该重复出现在全部
            if (userId.equals(record.getUserId()) && record.getIsGathered()){
                continue;
            }*/
            //当前用户已采集的笔记不应该重复出现在全部
            if (noteUsersMap.containsKey(record.getId())){
                continue;
            }
            //存作者信息，即用户信息，即昵称，头像
            UserDTO user = map.get(record.getUserId());
            vo.setAuthorName(user.getName());
            vo.setAuthorIcon(user.getIcon());
            vo.setAuthorId(record.getUserId());
            //如果 noteUsersMap 中包含该id，则说明该笔记被该用户采集了
            vo.setId(record.getId());
            if (CollUtil.isNotEmpty(noteUsersMap) && noteUsersMap.containsKey(record.getGatheredNoteId())){
                vo.setIsGathered(true);
                vo.setAuthorId(record.getAuthorId());
                UserDTO author = map.get(record.getAuthorId());
                vo.setAuthorName(author.getName());
                vo.setAuthorIcon(author.getIcon());
                vo.setId(record.getGatheredNoteId());
            }
            //存笔记id，内容，播放时间点，是否隐私，作者id，即用户id,创建时间
            vo.setContent(record.getContent());
            vo.setNoteMoment(record.getNoteMoment());
            vo.setIsPrivate(record.getIsPrivate());
            vo.setCreateTime(record.getCreateTime());

            list.add(vo);
        }
        return PageDTO.of(page, list);
    }

    private PageDTO<NoteVO> queryMyNote(NotePageQuery query, Long userId) {
        Page<Note> page = lambdaQuery()
                .eq(query.getCourseId() != null, Note::getCourseId, query.getCourseId())
                .eq(query.getSectionId() != null, Note::getSectionId, query.getSectionId())
                .eq(Note::getUserId, userId)
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<Note> records = page.getRecords();
        if (CollUtil.isEmpty(records)){
            return PageDTO.empty(page);
        }
        //2.通过stream获取采集用户id集合
        List<Long> authorIds = records.stream().map(Note::getAuthorId).collect(Collectors.toList());
        //3.根据id集合查询用户信息
        List<UserDTO> users = userClient.queryUserByIds(authorIds);
        //3.1将用户信息转为map
        Map<Long, UserDTO> map = users.stream().collect(Collectors.toMap(UserDTO::getId, user -> user));
        //4.查询我的用户信息
        UserDTO myInfo = userClient.queryUserById(userId);
        ArrayList<NoteVO> list = new ArrayList<>(records.size());
        for (Note record : records) {
            NoteVO vo = new NoteVO();

            if (record.getIsGathered()){
                UserDTO author = map.get(record.getAuthorId());
                //设置作者信息 作者id，名称，头像
                vo.setAuthorId(author.getId());
                vo.setAuthorName(author.getName());
                vo.setAuthorIcon(author.getIcon());
            }else {
                vo.setAuthorId(myInfo.getId());
                vo.setAuthorName(myInfo.getName());
                vo.setAuthorIcon(myInfo.getIcon());
            }
            //设置笔记信息 笔记id，内容，播放时间点，是否采集，是否隐私，创建时间
            vo.setId(record.getId());
            vo.setContent(record.getContent());
            vo.setNoteMoment(record.getNoteMoment());
            vo.setIsPrivate(record.getIsPrivate());
            vo.setIsGathered(record.getIsGathered());
            vo.setCreateTime(record.getCreateTime());
            list.add(vo);
        }
        return PageDTO.of(page, list);
    }
    @Override
    public PageDTO<AdminNoteVO> queryAdminNote(AdminNotePageQuery query) {
        //1.进行条件过滤
        boolean isTime=query.getBeginTime()!=null && query.getEndTime()!=null;
        //2.远程调用课程服务查询课程id
        boolean isName = StringUtils.isNotBlank(query.getName());
        List<Long> courseIds=null;
        if (isName){
            courseIds = courseClient.queryCoursesIdByName(query.getName());
            if (CollUtil.isEmpty(courseIds)){
                return null;
            }
        }
        //isName = CollUtil.isNotEmpty(courseIds) && isName;
        //3.根据条件进行分页查询
        Page<Note> page = this.lambdaQuery()
                .eq(BooleanUtil.isTrue(query.getHidden()), Note::getHidden, query.getHidden())
                .between(isTime, Note::getCreateTime, query.getBeginTime(), query.getEndTime())
                .in(isName, Note::getCourseId, courseIds)
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<Note> records = page.getRecords();
        if (CollUtil.isEmpty(records)){
            return PageDTO.empty(page);
        }

        //4.0 通过stream流获取课程id集合
        List<Long> cIds = records.stream().map(Note::getCourseId).collect(Collectors.toList());
        //4.2 远程调用课程服务查询课程信息 并转为map<courseId,CourseSimpleInfoDTO>
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(cIds);
        Map<Long, CourseSimpleInfoDTO> ccourseInfoMap = simpleInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, cInfo -> cInfo));
        //4.3 通过stream流获取章id集合
        List<Long> chapterIds = records.stream().map(Note::getChapterId).collect(Collectors.toList());
        //4.4 远程调用目录服务查询章信息 并转为map<章目录id,CourseSimpleInfoDTO>
        List<CataSimpleInfoDTO> chapterList = catalogueClient.batchQueryCatalogue(chapterIds);
        Map<Long, CataSimpleInfoDTO> chapterMap = chapterList.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, cInfo -> cInfo));
        //4.5 通过stream流获取小节id集合
        List<Long> sectionIds = records.stream().map(Note::getSectionId).collect(Collectors.toList());
        //4.6 远程调用目录服务查询小节信息 并转为map<小节目录id,CourseSimpleInfoDTO>
        List<CataSimpleInfoDTO> sectionList = catalogueClient.batchQueryCatalogue(sectionIds);
        Map<Long, CataSimpleInfoDTO> sectionMap = sectionList.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, cInfo -> cInfo));
        //4.7 获取id集合
        List<Long> noteIds = records.stream().map(Note::getId).collect(Collectors.toList());
        //4.8 查询用户笔记关联表，利用count 查询笔记被使用次数
        Map<Long,Long> countMap=noteUserService.queryusedTimes(noteIds);
        //4.9 查询用户信息
        List<UserDTO> users = userClient.queryUserByIds(records.stream().map(Note::getUserId).collect(Collectors.toList()));
        Map<Long, UserDTO> userMap = users.stream().collect(Collectors.toMap(UserDTO::getId, user -> user));
        //5.封装数据
        ArrayList<AdminNoteVO> list = new ArrayList<>(records.size());
        for (Note record : records) {
            AdminNoteVO vo = BeanUtil.copyProperties(record, AdminNoteVO.class);
            //课程名称
            vo.setCourseName(ccourseInfoMap.get(record.getCourseId()).getName());
            //章名称
            vo.setChapterName(chapterMap.get(record.getChapterId()).getName());
            //小节名称
            vo.setSectionName(sectionMap.get(record.getSectionId()).getName());
            //笔记被使用次数
            vo.setUsedTimes(0);
            if (countMap.get(record.getId())!=null ) {
                vo.setUsedTimes(countMap.get(record.getId()).intValue());
            }
            //作者名称
            vo.setAuthorName(userMap.get(record.getUserId()).getName());
            list.add(vo);
        }
        return PageDTO.of(page, list);
    }

    @Override
    public AdminNoteDetailVO queryNoteDetailToAdmin(Long id) {
        //1.查询笔记信息
        Note note = this.getById(id);
        if (note==null){
            throw new BizIllegalException("查询数据错误");
        }
        AdminNoteDetailVO vo = BeanUtil.copyProperties(note, AdminNoteDetailVO.class);
        //2.根据课程id查询课程信息
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(CollUtil.toList(note.getCourseId()));
        vo.setCourseName(simpleInfoList.get(0).getName());
        //3.根据章id查询章信息
        List<CataSimpleInfoDTO> chapterList = catalogueClient.batchQueryCatalogue(CollUtil.toList(note.getChapterId()));
        vo.setChapterName(chapterList.get(0).getName());
        //4.根据小节id查询小节信息
        List<CataSimpleInfoDTO> sectionList = catalogueClient.batchQueryCatalogue(CollUtil.toList(note.getSectionId()));
        vo.setSectionName(sectionList.get(0).getName());
        //5.获取三级id以及名称
        Long firstCateId = simpleInfoList.get(0).getFirstCateId();
        Long secondCateId = simpleInfoList.get(0).getSecondCateId();
        Long thirdCateId = simpleInfoList.get(0).getThirdCateId();
        List<CategoryBasicDTO> level = categoryClient.getAllOfOneLevel();
        //5.1转为map
        Map<Long, CategoryBasicDTO> categoryMap = level.stream().collect(Collectors.toMap(CategoryBasicDTO::getId, cInfo -> cInfo));
        String categoryNames = categoryMap.get(firstCateId).getName()
                +"/"+categoryMap.get(secondCateId).getName()
                +"/"+categoryMap.get(thirdCateId).getName();
        vo.setCategoryNames(categoryNames);
        //6.查询用户笔记关联表得到笔记被使用次数以及采集人集合
        List<NoteUser> list = noteUserService.lambdaQuery().eq(NoteUser::getNoteId, id).list();
        //6.1获取userId集合
        List<Long> userIds = list.stream().map(NoteUser::getUserId).collect(Collectors.toList());
        //6.2获取笔记被使用次数
        vo.setUsedTimes(userIds.size());
        //6.3获取用户信息 得到采集人集合
        List<UserDTO> users = userClient.queryUserByIds(userIds);
        List<String> gathers = users.stream().map(UserDTO::getName).collect(Collectors.toList());
        vo.setGathers(gathers);
        //7.查询用户信息 得到作者名称，作者电话
        UserDTO user = userClient.queryUserById(note.getAuthorId());
        vo.setAuthorPhone(user.getCellPhone());
        vo.setAuthorName(user.getName());
        return vo;
    }

    @Override
    public void hiddenOrShowNote(Long id, Integer hidden) {
        this.lambdaUpdate().eq(Note::getId, id).set(Note::getHidden, hidden).update();
    }
}



























